#include "saddr.hh"

using namespace NM;

Saddr::Saddr()
{
	addr4.sin_addr.s_addr = INADDR_ANY;
	addr6.sin6_addr       = in6addr_any;
	setDomain(IPV4);
}

Saddr::Saddr(int _domain)
{
	addr4.sin_addr.s_addr = INADDR_ANY;
	addr6.sin6_addr       = in6addr_any;
	setDomain(_domain);
}

Saddr::Saddr(const Saddr &_ref)
{
	if (&_ref != this)
	{
		type = _ref.type;
		if (type == IPV4)
			addr4 = _ref.addr4;
		else if (type == IPV6)
			addr6 = _ref.addr6;
	}
}

Saddr &Saddr::operator=(const Saddr &_ref)
{
	if (&_ref != this)
	{
		type = _ref.type;
		if (type == IPV4)
			addr4 = _ref.addr4;
		else if (type == IPV6)
			addr6 = _ref.addr6;
	}
	return *(this);
}

void 					Saddr::setDomain(int _domain)
{
    if (_domain == AF_INET6)
	{
		type = IPV6;
		addr6.sin6_family = AF_INET6;
	}
    else
    {
        type = IPV4;
        addr4.sin_family = AF_INET;
    }
}

void 					Saddr::setPort(int _port)
{
	if (type == IPV4)
		addr4.sin_port = htons(_port);
	else if (type == IPV6)
		addr6.sin6_port = htons(_port);
}

int 					Saddr::getPort()
{
	if (type == IPV4)
		return ntohs(addr4.sin_port);
	else if (type == IPV6)
		return ntohs(addr6.sin6_port);
	return 0;
}

void 					Saddr::setAddress(const string &_address)
{
	if (type == IPV4)
		inet_pton(AF_INET, _address.c_str(), &addr4.sin_addr.s_addr);
	else if (type == IPV6)
		inet_pton(AF_INET6, _address.c_str(), &addr6.sin6_addr.s6_addr);
}

const string 			&Saddr::getAddress()
{
	char 				buffer[INET6_ADDRSTRLEN];

	if (type == IPV4)
		inet_ntop(AF_INET, &addr4.sin_addr, buffer, sizeof(buffer));
	else if (type == IPV6)
		inet_ntop(AF_INET6, &addr6.sin6_addr, buffer, sizeof(buffer));

	address.assign(buffer);
	return address;
}

void 					Saddr::setName(const string &_name)
{
	struct addrinfo 		*hits = NULL;
	struct sockaddr_in 		*dest4;
	struct sockaddr_in6 	*dest6;
	int 					ret;

	ret = getaddrinfo(_name.c_str(), NULL, NULL, &hits);
	if (ret == 0)
	{
		if (type == IPV4)
		{
			dest4 = (struct sockaddr_in*)hits->ai_addr;
			addr4.sin_addr = dest4->sin_addr;
		}
		else if (type == IPV6)
		{
			dest6 = (struct sockaddr_in6*)hits->ai_addr;
			addr6.sin6_addr = dest6->sin6_addr;
		}
	}
}

int 					Saddr::getDomain()
{
	if (type == IPV6)
		return addr6.sin6_family;
	return addr4.sin_family;
}

struct sockaddr			*Saddr::getSaddr()
{
	if (type == IPV6)
		return (struct sockaddr*)&this->addr6;
	else
		return (struct sockaddr*)&this->addr4;
}

int 					Saddr::getSaddrSize()
{
	if (type == IPV6)
		return sizeof(this->addr6);
	return sizeof(this->addr4);
}
